package com.qdlc.p2p.biz.service.impl;

import java.math.BigDecimal;
import java.text.MessageFormat;
import java.util.List;
import java.util.Map;

import javax.annotation.Resource;

import com.qdlc.p2p.biz.service.*;
import com.qdlc.p2p.common.constant.*;
import com.qdlc.p2p.dal.dto.*;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.gson.Gson;
import com.qd.p2p.adapter.Response;
import com.qd.p2p.adapter.enums.ResponseStatus;
import com.qd.p2p.sina.pay.enums.AccountType;
import com.qd.p2p.sina.pay.enums.IdentityType;
import com.qdlc.p2p.biz.processor.event.RepayPayNoticeEvent;
import com.qdlc.p2p.biz.processor.event.TppDispatchValueEvent;
import com.qdlc.p2p.common.core.ReturnResult;
import com.qdlc.p2p.common.core.queue.QueueHandlers;
import com.qdlc.p2p.common.exception.BusinessException;
import com.qdlc.p2p.common.util.BeanCopierUtils;
import com.qdlc.p2p.common.util.BigDecimalUtil;
import com.qdlc.p2p.common.util.DataUtils;
import com.qdlc.p2p.common.util.DateUtil;
import com.qdlc.p2p.dal.common.SystemConfigHelper;
import com.qdlc.p2p.dal.dao.BorrowCollectionDao;
import com.qdlc.p2p.dal.dao.BorrowRepaymentDao;
import com.qdlc.p2p.dal.dao.BorrowTenderDao;
import com.qdlc.p2p.dal.dao.TppDao;
import com.qdlc.p2p.dal.model.TppModel;
import com.qdlc.p2p.dal.model.TppTradeLogModel;
import com.qdlc.p2p.dal.util.UserUtils;

@Service("borrowRepayPayService")
public class BorrowRepayPayServiceImpl extends AbstractPayService {

    private final static String BUSINESS_NAME = "还款本息代付-";

    /**
     * 代收交易Log
     */
    private ThreadLocal<TppTradeLog> collectTppTradeLogLocal = new ThreadLocal<TppTradeLog>();

    /**
     * memo
     */
    private ThreadLocal<Map<String, Object>> memoLocal = new ThreadLocal<Map<String, Object>>();

    /**
     * 投资人TppId
     */
    private ThreadLocal<String> tenderUserTppIdLocal = new ThreadLocal<String>();

    /**
     * 投资金额
     */
    private ThreadLocal<Double> repayAmountLocal = new ThreadLocal<Double>();

    /**
     * 预还款ID
     */
    private ThreadLocal<Long> borrowRepaymentIdLocal = new ThreadLocal<Long>();

    /**
     * 投资人利息管理费
     */
    private ThreadLocal<Double> interestManageLocal = new ThreadLocal<Double>();

    @Resource
    private BorrowRepaymentDao borrowRepaymentDao;

    @Resource
    private BorrowTenderDao tenderDao;

    @Resource
    private BorrowCollectionDao borrowCollectionDao;

    @Resource
    private TppDao tppDao;

    @Resource
    private BorrowCollectionDao collectionDao;

    @Resource
    private AccountService accountService;

    @Resource
    private CashAwardRuleService cashAwardRuleService;

    @Resource
    private UserService userService;

    @Resource
    @Qualifier("bfRPCRequestService")
    private RPCRequestService<Response, TppTradeLog> rpcRequestService;

    @Override
    public void analyzePars(Object... pars) {
        if (pars.length != 1) {
            throw new IllegalArgumentException("参数个数正确!");
        }
        try {
            TppTradeLog collectTppTradeLog = (TppTradeLog) pars[0]; // 代收交易Log
            if (collectTppTradeLog == null) {
                throw new IllegalArgumentException("参数类型正确!");
            }
            collectTppTradeLogLocal.set(collectTppTradeLog);
        } catch (Exception ex) {
            throw new IllegalArgumentException("参数类型正确!");
        }
    }

    @Override
    public TppTradeLog getTppTradeLog() {
        // 代收交易log
        TppTradeLog collectTppTradeLog = collectTppTradeLogLocal.get();

        // 创建代付订单
        TppTradeLog newTppTradeLog = new TppTradeLog();
        // 订单无效或失败 说明是重新发起的
        if (TradeStatus.TRADE_STATUS_INVALID.getStatus().equals(collectTppTradeLog.getTradeStatus())
                || TradeStatus.TRADE_STATUS_FAILED.getStatus().equals(collectTppTradeLog.getTradeStatus())) {
            BeanCopierUtils.copyProperties(collectTppTradeLogLocal.get(), newTppTradeLog);
            newTppTradeLog.setId(0l);
        } else {
            newTppTradeLog.setTppUserCustId(collectTppTradeLog.getTppUserCustId()); // 借款人
            newTppTradeLog.setToTppUserCustId(tenderUserTppIdLocal.get()); // 投资人
            newTppTradeLog.setIdentityType(IdentityType.UID.toString()); // 投资人都是UID
            newTppTradeLog.setMoney(repayAmountLocal.get()); // 还款金额(本金+利息 或 加息利息)
            newTppTradeLog.setBorrowId(collectTppTradeLog.getBorrowId()); // 标ID
            newTppTradeLog.setBorrowRepaymentId(borrowRepaymentIdLocal.get()); // 还款ID
            newTppTradeLog.setAssociateOrderId(collectTppTradeLog.getOrderNo());
            newTppTradeLog.setMemo((new Gson()).toJson(memoLocal.get()));
            newTppTradeLog.setTradeType(TradeCode.C2004.toString());
            newTppTradeLog.setServiceType(Summary.REPAY.getSummaryType());

            // 应收利息管理费0以上 进行分帐
            if (interestManageLocal.get() != null && interestManageLocal.get() > 0) {
                StringBuilder sb = new StringBuilder();
                sb.append(tenderUserTppIdLocal.get()).append("^");
                sb.append(IdentityType.UID.toString()).append("^");
                sb.append(AccountType.SAVING_POT.toString()).append("^");
                sb.append(SystemConfigHelper.getValue(SystemConfigHelper.Nid.MEMBER_EMAIL)).append("^");
                sb.append(IdentityType.EMAIL.toString()).append("^");
                sb.append(AccountType.BASIC.toString()).append("^");
                sb.append(interestManageLocal.get()).append("^");
                sb.append("利息管理费");
                newTppTradeLog.setSplitList(sb.toString());
            }
        }
        return newTppTradeLog;
    }

    @Override
    public List<TppTradeLog> createOrders(Object... pars) {
        analyzePars(pars);

        // 代收交易log
        TppTradeLog collectTppTradeLog = collectTppTradeLogLocal.get();

        BorrowRepayment borrowRepayment = borrowRepaymentDao.find(collectTppTradeLog.getBorrowRepaymentId());

        // 应还金额累积
        double repayTotalAmount = 0;
        // 代付订单
        List<TppTradeLog> tppTradeLogs = Lists.newArrayList();

        Map<String, Object> memo = Maps.newHashMap();
        // 本息待收订单生成
        List<BorrowCollection> borrowCollectionList = borrowCollectionDao.list(collectTppTradeLog.getBorrowId(), borrowRepayment.getPeriod());
        for (BorrowCollection borrowCollection : borrowCollectionList) {
            // 收款用户 第三方TPP_ID
            String tenderUserTppId = UserUtils.getUserTppCustId(borrowCollection.getUser().getUserId());
            // 待付利息
            double interest = borrowCollection.getInterest();
            // 本金加利息
            double repayAmount = BigDecimalUtil.add(borrowCollection.getCapital(), interest);
            // 应还金额累积
            repayTotalAmount = BigDecimalUtil.add(repayTotalAmount, repayAmount);

            // 应收取 投资人利息管理费
            double interestManage = BigDecimalUtil.round(borrowCollection.getManageFee(), 2);

            // 备注重要信息
            memo.put("collectionId", borrowCollection.getId());
            memo.put("userId", borrowCollection.getUser().getUserId());
            memo.put("tppUserId", tenderUserTppId);
            memo.put("tppUserName", borrowCollection.getUser().getUserName());
            if (interestManage > 0) {
                memo.put("interestManage", interestManage);
                interestManageLocal.set(interestManage);
            }

            memoLocal.set(memo);
            tenderUserTppIdLocal.set(tenderUserTppId);
            repayAmountLocal.set(repayAmount);
            borrowRepaymentIdLocal.set(borrowRepayment.getId());
            tppTradeLogs.add(createOrder(pars));
        }
        // 代收的加息金额 与 应还的加息金额不一致 说明程序有bug
        BigDecimal repayTotalAmountDecimal = new BigDecimal(repayTotalAmount);
        BigDecimal moneyDecimal = new BigDecimal(collectTppTradeLog.getMoney());
        if (repayTotalAmountDecimal.compareTo(moneyDecimal) != 0) {
            throw new BusinessException(MessageFormat.format("第{0}期 还款代收本息金额 与 还款代付本息金额不一致,无法完成代付! 代收本息金额:{1} 代付本息金额:{2}",
                    borrowRepayment.getPeriod(), collectTppTradeLog.getMoney(), repayTotalAmount));
        }
        return tppTradeLogs;
    }


    @Override
    public ReturnResult requestOrder(TppTradeLog tppTradeLog) {
        Response response = rpcRequestService.repayPayRequest(tppTradeLog);
        // 未知状态通知 交由消息队列处理
        if (response == null || response.getStatus() == ResponseStatus.UN_KNOW) {
            notice(tppTradeLog, TradeStatus.TRADE_STATUS_UN_KNOW);
            return new ReturnResult(true, "系统处理中!请查看投标结果!");
        }
        // 代付调用成功
        if (response.getStatus() == ResponseStatus.SUCCESS) {
            tppTradeLog.setRemark(getBusinessName().concat("提交成功"));
            tppTradeService.update(tppTradeLog);
            // 成功通知
            notice(tppTradeLog, TradeStatus.TRADE_STATUS_FINISHED);
            requestOrderSuccess(tppTradeLog); // 请求成功处理
        } else if (response.getStatus() == ResponseStatus.FAILURE) {
            String message = response == null ? "RPC调用失败" : MessageFormat.format("代付失败! resCode:{0} resMessage:{1}",
                    response.getResponseCode(),
                    response.getResponseMsg());
            String responseMessage = response == null ? "RPC调用失败" : response.getResponseMsg();
            logger.info(message);

            // 置为废单
            tppTradeLog.setTradeStatus(TradeStatus.TRADE_STATUS_INVALID.getStatus());
            tppTradeLog.setRemark(getBusinessName().concat("提交失败-" + responseMessage));
            tppTradeService.update(tppTradeLog);
            requestOrderFail(tppTradeLog); // 请求失败处理
            return new ReturnResult(true, message);
        }
        return ReturnResult.SUCCESS;
    }

    @Override
    public void requestOrderFail(TppTradeLog tppTradeLog) {
        // 保存调度任务信息
        Tpp tpp = new Tpp();
        tpp.setStatus(TppModel.STATUS_FAIL);
        tpp.setServiceType(TppModel.DOREPAY);
        tpp.setTppType(SinaConstant.TRADE_SERVICE_REPAY);
        tpp.setTppUserCustId(tppTradeLog.getTppUserCustId());// 借款人托管账户ID
        tpp.setMoney(tppTradeLog.getMoney());
        tpp.setOrderId(tppTradeLog.getOrderNo());
        tpp.setOrderDate(DateUtil.dateStr7(tppTradeLog.getAddTime()));
        tpp.setExtended(tppTradeLog.getBorrowRepaymentId() + "");// 还款ID
        tpp.setTradeType(tppTradeLog.getTradeType());
        tpp.setRespDesc(tppTradeLog.getRemark());
        tpp.setAddTime(DateUtil.getNow());
        tpp.setTppBorrowId(tppTradeLog.getBorrowId() + "");// 标ID
        tppDao.save(tpp);

        // 调度任务交由队列处理(延时处理)
        if (tppTradeLog.getAutoDispatch() != TppTradeLogModel.IS_AUTO) {// 防止重复处理
            TppModel tppModel = TppModel.instance(tpp);
            TppDispatchValueEvent tppDispatchValueEvent = new TppDispatchValueEvent();
            tppDispatchValueEvent.setTppModel(tppModel);
            QueueHandlers.put(tppDispatchValueEvent);
        }
    }

    @Override
    public void tradeFinish(TppTradeLog tppTradeLog, String depositStatus, double tradeAmount) {
        super.tradeFinishForStatus(tppTradeLog, depositStatus, tradeAmount);

        // logMemo
        Map<String, Object> memo = DataUtils.getMemo(tppTradeLog.getMemo());

        long userId = DataUtils.toLong(memo.get("userId")); // 用户ID
        long collectionId = DataUtils.toLong(memo.get("collectionId")); // 还款记录ID

        // 更新还款记录
        BorrowCollection borrowCollection = borrowCollectionDao.find(collectionId);
        // 防止重复增加资金
        if (borrowCollection.getStatus() == BorrowCollectionStatus.ALREADY_REPAYMENT) {
            logger.info("已经还款,请勿重复还款!");
            return;
        }

        borrowCollection.setStatus(BorrowCollectionStatus.ALREADY_REPAYMENT); // 已还款
        borrowCollection.setRepaymentYesTime(DateUtil.getNow()); // 还款时间
        borrowCollection.setRepaymentYesAccount(tradeAmount); // 还款金额(本金+利息)
        collectionDao.update(borrowCollection);

        // 更新投标记录
        BorrowTender tender = borrowCollection.getTender();
        tender.setRepaymentYesAccount(BigDecimalUtil.add(tender.getRepaymentYesAccount(), tradeAmount));
        tender.setRepaymentYesInterest(BigDecimalUtil.add(tender.getRepaymentYesInterest(), borrowCollection.getInterest()));
        tender.setWaitAccount(BigDecimalUtil.add(tender.getWaitAccount(), -borrowCollection.getRepaymentAccount()));
        tender.setWaitInterest(BigDecimalUtil.add(tender.getWaitInterest(), -borrowCollection.getInterest()));
        tenderDao.update(tender);

        // 资金Log生成用
        Global.setTransfer("web_url", WEB_URL);
        Global.setTransfer("borrow", tender.getBorrow());

        // 收回本金(可用增加)
        Double capital = new Double(borrowCollection.getCapital());
        if (capital.compareTo(0d) != 0) {
            Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.CAPITAL_COLLECT);
            Global.setTransfer("money", borrowCollection.getCapital());
            accountService.revokeCapital(userId, tender.getBorrow().getUser().getUserId(), borrowCollection.getCapital());
        }

        // 收回利息(可用增加)
        Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.INTEREST_COLLECT);
        Global.setTransfer("money", borrowCollection.getInterest());
        // 利息管理费
        double interestManage = borrowCollection.getManageFee();
        // 扣除利息管理费 入可用
        double remainInterest = BigDecimalUtil.sub(borrowCollection.getInterest(), interestManage);
        accountService.revokeInterest(userId, tender.getBorrow().getUser().getUserId(), remainInterest);

        // 收取利息管理费
        if (interestManage > 0) {
            Global.setTransfer(LogTplNid.LOG_TPL_KEY, LogTplNid.INVESTOR_MANAGE_FEE);
            Global.setTransfer("money", interestManage);
            accountService.revokeInterestManageFee(userId, GeneralAccountType.PLATFORM, interestManage);
        }
        // 向投资人发送还款成功通知，不做任何资金处理

    }

    @Override
    public void tradeSuccess(TppTradeLog tppTradeLog, String depositStatus) {
        super.tradeSuccessForStatus(tppTradeLog, depositStatus);
    }

    @Override
    public void tradeFail(TppTradeLog tppTradeLog, String depositStatus) {
        super.tradeFailForStatus(tppTradeLog, depositStatus);
    }

    @Override
    public String getCallBackUrl() {
        return WEB_URL.concat(NotifyUrl.REPAY_NOTIFY_PAY_URL).concat(".html");
    }

    @Override
    public String getBusinessName() {
        return BUSINESS_NAME;
    }

    /**
     * 发送投标通知 交由队列来执行
     */
    private void notice(TppTradeLog tppTradeLog, TradeStatus tradeStatus) {
        RepayPayNoticeEvent event = new RepayPayNoticeEvent();
        event.setClientIp(Global.getIP());
        event.setTradeStatus(tradeStatus);
        event.setTppTradeLog(tppTradeLog);
        event.setOutOrderNo(tppTradeLog.getOrderNo());
        event.setDepositAmount(tppTradeLog.getMoney());
        QueueHandlers.put(event);
    }
}